﻿using System;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using System.Threading.Tasks;

namespace Sayook.Framework.Tools
{
    /// <summary>
    /// Json序列化
    /// </summary>
    public static class JsonHelper
    {
        private static readonly JsonSerializerOptions _jsonSerializerOptions;

        static JsonHelper()
        {
            _jsonSerializerOptions = new JsonSerializerOptions
            {
                AllowTrailingCommas = true,
                IgnoreNullValues = true,
                //序列化时中文会被编码
                Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
            };
            //日期格式转换
            _jsonSerializerOptions.Converters.Add(new DateTimeJsonConverter());
            _jsonSerializerOptions.Converters.Add(new DateTimeNullableConverter());
        }

        /// <summary>
        /// 序列化
        /// </summary>
        /// <param name="obj">被序列化</param>
        /// <returns>json string</returns>
        public static string ToJson(this object obj)
        {
            if (obj == null) return null;

            return JsonSerializer.Serialize(obj, _jsonSerializerOptions);
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonStr"></param>
        /// <returns></returns>
        public static T FormJson<T>(this string jsonStr)
        {
            if (string.IsNullOrWhiteSpace(jsonStr)) return default;

            return JsonSerializer.Deserialize<T>(jsonStr, _jsonSerializerOptions);
        }

        public static async Task<T> FormJsonAsync<T>(this string jsonStr)
        {
            if (string.IsNullOrWhiteSpace(jsonStr)) return default;
            byte[] array = Encoding.Default.GetBytes(jsonStr);
            MemoryStream stream = new MemoryStream(array);
            return await JsonSerializer.DeserializeAsync<T>(stream, _jsonSerializerOptions);
        }
    }

    public class DateTimeJsonConverter : JsonConverter<DateTime>
    {
        private readonly string _dateFormatString;

        public DateTimeJsonConverter()
        {
            _dateFormatString = "yyyy-MM-dd HH:mm:ss";
        }

        public DateTimeJsonConverter(string dateFormatString)
        {
            _dateFormatString = dateFormatString;
        }

        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            return DateTime.Parse(reader.GetString());
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString(_dateFormatString));
        }
    }

    public class DateTimeNullableConverter : JsonConverter<DateTime?>
    {
        private readonly string _dateFormatString;

        public DateTimeNullableConverter()
        {
            _dateFormatString = "yyyy-MM-dd HH:mm:ss";
        }

        public DateTimeNullableConverter(string dateFormatString)
        {
            _dateFormatString = dateFormatString;
        }

        public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var value = reader.GetString();
            return string.IsNullOrWhiteSpace(value) ? default(DateTime?) : DateTime.Parse(value);
        }

        public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value?.ToString(_dateFormatString));
        }
    }
}